<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>基础扫雷</title>
  <link rel="icon" href="/assets/close.svg" />
  <style>
    :root { color-scheme: light dark; }
    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif; margin: 0; padding: 1rem; display: grid; place-items: start center; gap: 1rem; }
    header { display: flex; align-items: center; gap: .75rem; }
    h1 { font-size: 1.25rem; margin: 0; }
    .toolbar { display: flex; align-items: center; gap: .5rem; margin-top: .5rem; }
    button { cursor: pointer; padding: .5rem .75rem; border: 1px solid #8883; border-radius: .5rem; background: #fff2; }
    .board { display: grid; grid-template-columns: repeat(var(--cols), 28px); grid-auto-rows: 28px; gap: 2px; background: #9993; padding: 4px; border-radius: .5rem; }
    .cell { width: 28px; height: 28px; display: grid; place-items: center; font-weight: 700; user-select: none; border-radius: .25rem; background: #eee; color: #333; box-shadow: inset 0 0 0 1px #0001; }
    .cell.hidden { background: #cfd8dc; color: transparent; }
    .cell.mine { background: #ef9a9a; color: #b71c1c; }
    .cell.flag { background: #ffe082; color: #ef6c00; }
    .status { font-variant-numeric: tabular-nums; }
    footer { color: #666; font-size: .85rem; }
  </style>
</head>
<body>
  <header>
    <img src="/assets/close.svg" alt="icon" width="24" height="24" />
    <h1>基础扫雷</h1>
  </header>
  <div class="toolbar">
    <label>行：<input id="rows" type="number" value="9" min="5" max="24" style="width:4rem"></label>
    <label>列：<input id="cols" type="number" value="9" min="5" max="30" style="width:4rem"></label>
    <label>雷：<input id="mines" type="number" value="10" min="1" max="200" style="width:5rem"></label>
    <button id="restart">重新开始</button>
    <span class="status" id="status">🙂 游戏中</span>
  </div>

  <div id="board" class="board"></div>

  <footer>
    左键：翻开 | 右键：标记。首次点击保证非雷且会展开空白区域。
  </footer>

  <script>
    const boardEl = document.getElementById('board');
    const statusEl = document.getElementById('status');
    const rowsEl = document.getElementById('rows');
    const colsEl = document.getElementById('cols');
    const minesEl = document.getElementById('mines');
    const restartBtn = document.getElementById('restart');

    let R=9, C=9, M=10;
    let firstClick = true;
    let grid = []; // cells: {mine, reveal, flag, around}
    let revealedCount = 0;
    let alive = true;

    function clamp(v,min,max){return Math.max(min, Math.min(max, v));}

    function init() {
      R = clamp(Number(rowsEl.value)||9, 5, 24);
      C = clamp(Number(colsEl.value)||9, 5, 30);
      const maxMines = Math.max(1, Math.min(R*C-1, Number(minesEl.value)||10));
      M = clamp(maxMines, 1, 200);
      firstClick = true;
      revealedCount = 0;
      alive = true;
      statusEl.textContent = '🙂 游戏中';

      grid = Array.from({length:R}, () => Array.from({length:C}, () => ({
        mine:false, reveal:false, flag:false, around:0
      })));
      render();
    }

    function inBounds(r,c){return r>=0 && r<R && c>=0 && c<C;}

    function neighbors(r,c){
      const res=[];
      for(let dr=-1; dr<=1; dr++) for(let dc=-1; dc<=1; dc++){
        if(dr===0 && dc===0) continue;
        const nr=r+dr, nc=c+dc;
        if(inBounds(nr,nc)) res.push([nr,nc]);
      }
      return res;
    }

    function placeMines(safeR, safeC) {
      const cells=[];
      for(let r=0;r<R;r++) for(let c=0;c<C;c++){
        // 保证首次点击位置与其邻居无雷
        if(Math.abs(r-safeR)<=1 && Math.abs(c-safeC)<=1) continue;
        cells.push([r,c]);
      }
      // 洗牌
      for(let i=cells.length-1; i>0; i--){
        const j = Math.floor(Math.random()*(i+1));
        [cells[i], cells[j]] = [cells[j], cells[i]];
      }
      for(let i=0; i<M && i<cells.length; i++){
        const [r,c] = cells[i];
        grid[r][c].mine = true;
      }
      // 统计 around
      for(let r=0;r<R;r++) for(let c=0;c<C;c++){
        if(grid[r][c].mine) continue;
        grid[r][c].around = neighbors(r,c).reduce((acc,[nr,nc])=>acc+(grid[nr][nc].mine?1:0),0);
      }
    }

    function floodReveal(sr, sc){
      const q=[[sr,sc]];
      while(q.length){
        const [r,c]=q.shift();
        const cell=grid[r][c];
        if(cell.reveal || cell.flag) continue;
        cell.reveal=true; revealedCount++;
        if(cell.around===0){
          for(const [nr,nc] of neighbors(r,c)){
            if(!grid[nr][nc].reveal && !grid[nr][nc].mine){ q.push([nr,nc]); }
          }
        }
      }
    }

    function checkWin(){
      const totalSafe = R*C - M;
      if(revealedCount >= totalSafe){
        alive=false; statusEl.textContent='😎 胜利';
        // 自动展示所有雷
        for(let r=0;r<R;r++) for(let c=0;c<C;c++) if(grid[r][c].mine) grid[r][c].reveal=true;
        render();
      }
    }

    function openCell(r,c){
      if(!alive) return;
      const cell=grid[r][c];
      if(cell.reveal || cell.flag) return;
      if(firstClick){
        placeMines(r,c);
        firstClick=false;
      }
      cell.reveal=true; revealedCount++;
      if(cell.mine){
        alive=false; statusEl.textContent='💥 失败';
        // 展示所有雷
        for(let rr=0;rr<R;rr++) for(let cc=0;cc<C;cc++) if(grid[rr][cc].mine) grid[rr][cc].reveal=true;
        render(); return;
      }
      if(cell.around===0){ floodReveal(r,c); }
      checkWin();
      renderCell(r,c);
    }

    function toggleFlag(r,c){
      if(!alive) return;
      const cell=grid[r][c];
      if(cell.reveal) return;
      cell.flag = !cell.flag;
      renderCell(r,c);
    }

    function render(){
      boardEl.style.setProperty('--cols', C);
      boardEl.innerHTML='';
      for(let r=0;r<R;r++){
        for(let c=0;c<C;c++){
          const div=document.createElement('div');
          div.className='cell hidden';
          div.dataset.r=r; div.dataset.c=c;
          div.oncontextmenu = (e)=>{ e.preventDefault(); toggleFlag(r,c); };
          div.onclick = ()=> openCell(r,c);
          boardEl.appendChild(div);
          renderCell(r,c, div);
        }
      }
    }

    function renderCell(r,c, node){
      const cell=grid[r][c];
      const el = node || [...boardEl.children][r*C + c];
      el.classList.remove('mine','flag','hidden');
      el.textContent='';
      if(!cell.reveal){
        el.classList.add('hidden');
        if(cell.flag){ el.classList.add('flag'); el.textContent='⚑'; }
        return;
      }
      if(cell.mine){ el.classList.add('mine'); el.textContent='💣'; return; }
      if(cell.around>0){ el.textContent=String(cell.around); }
    }

    restartBtn.onclick = () => init();
    init();
  </script>
</body>
</html>
